/******************************************************************
 * @version      : 1.0
 * @Author       : zhl
 * @Date         : 2023-05-04 15:07:10
 * @LastEditors  : zhl
 * @E-Mail       : zhll168@163.com
 * @Description  : 业务描述
 ******************************************************************/
#include "IModuleManager.h"
#include "moduleManager.h"
#include "logger.h"
#include "common.h"
#include "findfirst.h"
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>


char module_dir[256] = {0};

T_HASHMAP *g_modules;

T_IMODULE *getModule(T_IMODULE* module){

    if((NULL == module) || (NULL == module->flag()) || (1 > strlen(module->flag())) || (NULL == g_modules)){
        return NULL;
    }
    return (T_IMODULE *)hashmap_get(g_modules, module);
}
char *strToUpper(char *str) {
    char *tmpStr = str;
    if(NULL == str){
        return str;
    }
    while (*tmpStr != '\0') {
        *tmpStr = (char)toupper(*tmpStr);
        tmpStr++;
    }
    return str;
    }
int get_files_by_extension(const char *dir, const char *extension, T_IMODULE_FILE_LIST** list_files)
{
    intptr_t    handle;
    _finddata_t findData;
    int   num = 0;
    char tmpDir[256] = {0};

    if((NULL == dir) || (1 > strlen(dir))){
        dir = "./";
    }
    if((NULL == extension) || (1 > strlen(extension))){
        extension = "";
    }
    int len = strlen(dir) + 4;

    char *tmpPath = (char *)malloc(len);
    if(snprintf(tmpPath, len, "%s/*", dir) < 1){
        free(tmpPath);
        return -1;
    }
    handle = _findfirst(tmpPath, &findData);    // 查找目录中的第一个文件
    if(handle == -1)
    {
        free(tmpPath);
        log_file_w(NULL, "Failed to find first file! %s", strerror(errno));
        return -1;
    }
    //
    do
    {
        if(findData.attrib & _A_SUBDIR){
            if(strcmp(findData.name, ".") != 0
            && strcmp(findData.name, "..") != 0){    //是否是子目录并且不为"."或".."
                snprintf(tmpDir, sizeof(tmpDir), "%s/%s", dir, findData.name);
                log_file_i(NULL, "遍历目录: %s", tmpDir);
                get_files_by_extension(tmpDir, extension, list_files);
            }
        }else{
            log_file_i("文件名称: %s\t大小: %d", findData.name ,findData.size);
            strncpy(tmpDir, findData.name, sizeof(tmpDir));
            char *tmp_ext1 = get_extension(tmpDir);
            char* ext1 = "";
            if(NULL != tmp_ext1){
                ext1 = tmp_ext1;
            }            
            char* ext2 = "mod";
            if(NULL != extension){
                ext2 = (char *)extension;
            }
            strToUpper(ext1);
            strToUpper(ext2);
            if((NULL == extension) || (1 > strlen(extension))){
                snprintf(tmpDir, sizeof(tmpDir), "%s/%s", dir, findData.name);
                // if(NULL == *list_files){
                //     *list_files = (T_IMODULE_FILE_LIST*)malloc(sizeof(T_IMODULE_FILE_LIST));
                //     (*list_files)->head = (NULL == (*list_files)->head) ? *list_files:NULL;
                //     (*list_files)->next = NULL;
                // }
                // (*list_files)->fileName = (char *)malloc(strlen(tmpDir) + 1);//假设肯定会成功
                // strcpy((*list_files)->fileName, tmpDir);
                // *list_files = (*list_files)->next;
                log_w("未知模块：%s", tmpDir);
            }else{
                if(0 == strcmp(ext2, ext2)){
                    snprintf(tmpDir, sizeof(tmpDir), "%s/%s", dir, findData.name);
                    if(NULL == *list_files){
                        *list_files = (T_IMODULE_FILE_LIST*)malloc(sizeof(T_IMODULE_FILE_LIST));
                        if(NULL == (*list_files)->head){
                            (*list_files)->head = *list_files;
                        }
                        (*list_files)->next = NULL;
                    }
                    (*list_files)->fileName = (char *)malloc(strlen(tmpDir) + 1);//假设肯定会成功
                    strcpy((*list_files)->fileName, tmpDir);
                    *list_files = (*list_files)->next;
                    num++;
                }
            }
        }
            
    } while (_findnext(handle, &findData) == 0);    // 查找目录中的下一个文件
    free(tmpPath);
    _findclose(handle);    // 关闭搜索句柄
    *list_files = (*list_files)->head;
    return num;
}
int moduleCompare(const void *module1, const void *module2, void *data) {
    const T_IMODULE* mod1 = (const T_IMODULE *)module1;
    const T_IMODULE* mod2 = (const T_IMODULE *)module2;
    if(NULL == mod1){
        return -1;
    }
    if(NULL == mod2){
        return 1;
    }
    return strcmp(mod1->flag(), mod2->flag());
}

bool moduleIter(const void *module, void *udata) {
    const T_IMODULE* mod = (const T_IMODULE *)module;
    if(NULL == mod){
        return false;
    }
    log_i("模块标识：%s", mod->flag());
    return true;
}

uint64_t moduleHash(const void *module, uint64_t seed0, uint64_t seed1) {
    const T_IMODULE* mod = (const T_IMODULE *)module;
    return hashmap_sip(mod->flag(), strlen(mod->flag()), seed0, seed1);
}
//可优化，拆分为多个方法
void loadModules(const char *module_dir){
    /* 测试模块动态加载 */
    T_IMODULE_FILE_LIST* list_files;
    T_IMODULE_FILE_LIST* head;
    g_modules = hashmap_new(sizeof(T_IMODULE), 0, 0, 0, moduleHash, moduleCompare, NULL, NULL);
    if(NULL == g_modules){
        return ;
    }
    //测试用，正式版本时需要改动参数
    if(1 > get_files_by_extension(module_dir, "mod", &list_files)){
        return ;
    }
    head = list_files;
    // for(head = list_files; head != NULL; head = head->next){
    while(NULL != head){
        if(0 > load_module(head->fileName)){
            log_file_w(NULL, "加载模块%s失败。", head->fileName);
            continue;
        }
        T_IMODULE* module = (T_IMODULE*)calloc(1, sizeof(T_IMODULE));
        hashmap_set(g_modules, module);

        module->flag = function(FUNC_FLAG_NAME_STR);
        if(NULL == module->flag){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_FLAG_NAME_STR);
            continue ;
        }        
        char* module_name = (char *)module->flag();
        if((NULL == module->flag()) || (1 > strlen(module->flag()))){
        }
        module->init = function(FUNC_INIT_NAME_STR);
        if(NULL == module->init){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_INIT_NAME_STR);
        }
        module->reset = function(FUNC_RESET_NAME_STR);
        if(NULL == module->reset){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_RESET_NAME_STR);
        }
        module->quit = function(FUNC_QUIT_NAME_STR);
        if(NULL == module->quit){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_QUIT_NAME_STR);
        }
        module->run = function(FUNC_RUN_NAME_STR);
        if(NULL == module->run){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_RUN_NAME_STR);
        }
        module->destroy = function(FUNC_DESTROY_NAME_STR);
        if(NULL == module->destroy){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_DESTROY_NAME_STR);
        }
        module->packet = function(FUNC_PACKET_NAME_STR);
        if(NULL == module->packet){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_PACKET_NAME_STR);
        }
        module->unpacket = function(FUNC_UNPACKET_NAME_STR);
        if(NULL == module->unpacket){
            log_file_w(NULL, "从%s模块中，未找到%s方法。", head->fileName, FUNC_UNPACKET_NAME_STR);
        }
        list_files = list_files->next;
        free(head->fileName);
        free(head);
        free(module);
        head = list_files;
    }
}

void redirectModulepath(){
    char path[256] = {0};
    if(NULL == getcwd(path, sizeof(path))){
        snprintf(path, sizeof(path), "/usr/local/ped/bin");
    }
    snprintf(module_dir, sizeof(module_dir),"%s/../module",path);
    log_i("work dir:%s  module dir:%s", path, module_dir);
}

//卸载module
void moduleDestroy(){
    size_t iter = 0;
    void *mod = NULL;
    while (hashmap_iter(g_modules, &iter, &mod)) {
        T_IMODULE *module = mod;
        if(NULL != module){
            if(NULL != module->destroy){
                module->destroy();
            }
        }
    }
    hashmap_free(g_modules);
}

//加载module
void moduleInit(){
    size_t iter  = 0;
    void   *item = NULL;

    redirectModulepath();
    loadModules(module_dir);

    if(NULL == g_modules){
        log_file_w(NULL, "加载模块失败。");
        return;
    }
    while (hashmap_iter(g_modules, &iter, &item)) {
        const T_IMODULE *module = item;
        if(NULL != module){
            if(NULL != module->init){
                module->init();
            }
            if(NULL != module->run){
                module->run();
            }
        }
    }
}